// Copyright (C) 2010 Félix Cloutier.

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

#include "JitRecompiler.h"
#include <cstring>

namespace LLVMJit
{

#define INST(name) \
	void JitRecompiler::name(UGeckoInstruction inst, JitFunctionContext& functionContext)

INST(DispatchTable4)
{
	InstructionRecompiler instructionFunction = dispatchTable4[inst.SUBOP10];
	(this->*instructionFunction)(inst, functionContext);
}

INST(DispatchTable19)
{
	InstructionRecompiler instructionFunction = dispatchTable19[inst.SUBOP10];
	(this->*instructionFunction)(inst, functionContext);
}

INST(DispatchTable31)
{
	InstructionRecompiler instructionFunction = dispatchTable31[inst.SUBOP10];
	(this->*instructionFunction)(inst, functionContext);
}

INST(DispatchTable59)
{
	InstructionRecompiler instructionFunction = dispatchTable59[inst.SUBOP5];
	(this->*instructionFunction)(inst, functionContext);
}

INST(DispatchTable63)
{
	InstructionRecompiler instructionFunction = dispatchTable63[inst.SUBOP10];
	(this->*instructionFunction)(inst, functionContext);
}

#define COUNT(table)	(sizeof (table) / sizeof *(table))
void JitRecompiler::RemapInstructions()
{
	struct InstructionPair
	{
		u32 opcode;
		InstructionRecompiler function;
	};
	
	InstructionPair table4[] =
	{
		{0, 	&JitRecompiler::ps_cmpu0},
		{32, 	&JitRecompiler::ps_cmpo0},
		{40, 	&JitRecompiler::ps_neg},
		{136,	&JitRecompiler::ps_nabs},
		{264,	&JitRecompiler::ps_abs},
		{64,	&JitRecompiler::ps_cmpu1},
		{72,	&JitRecompiler::ps_mr},
		{96,	&JitRecompiler::ps_cmpo1},
		{528,	&JitRecompiler::ps_merge00},
		{560,	&JitRecompiler::ps_merge01},
		{592,	&JitRecompiler::ps_merge10},
		{624,	&JitRecompiler::ps_merge11},
		
		{1014,	&JitRecompiler::dcbz_l},
	};
	
	InstructionPair table4_2[] = 
	{
		{10, 	&JitRecompiler::ps_sum0},
		{11, 	&JitRecompiler::ps_sum1},
		{12, 	&JitRecompiler::ps_muls0},
		{13, 	&JitRecompiler::ps_muls1},
		{14, 	&JitRecompiler::ps_madds0},
		{15, 	&JitRecompiler::ps_madds1},
		{18, 	&JitRecompiler::ps_div},
		{20, 	&JitRecompiler::ps_sub},
		{21, 	&JitRecompiler::ps_add},
		{23, 	&JitRecompiler::ps_sel},
		{24, 	&JitRecompiler::ps_res},
		{25, 	&JitRecompiler::ps_mul},
		{26, 	&JitRecompiler::ps_rsqrte},
		{28, 	&JitRecompiler::ps_msub},
		{29, 	&JitRecompiler::ps_madd},
		{30, 	&JitRecompiler::ps_nmsub},
		{31, 	&JitRecompiler::ps_nmadd},
	};
	
	InstructionPair table4_3[] =
	{
		{6,		&JitRecompiler::psq_lx},
		{7, 	&JitRecompiler::psq_stx},
		{38,	&JitRecompiler::psq_lux},
		{39,	&JitRecompiler::psq_stux},
	};
	
	InstructionPair table19[] =
	{
		{528,	&JitRecompiler::bcctrx},
		{16,	&JitRecompiler::bclrx},
		{257,	&JitRecompiler::crand},
		{129,	&JitRecompiler::crandc},
		{289,	&JitRecompiler::creqv},
		{225,	&JitRecompiler::crnand},
		{33,	&JitRecompiler::crnor},
		{449,	&JitRecompiler::cror},
		{417,	&JitRecompiler::crorc},
		{193,	&JitRecompiler::crxor},
														   
		{150,	&JitRecompiler::isync},
		{0,		&JitRecompiler::mcrf},
														   
		{50,	&JitRecompiler::rfi},
		{18,	&JitRecompiler::rfid},
	};
	
	InstructionPair table31[] =
	{
		{28,	&JitRecompiler::andx},
		{60,	&JitRecompiler::andcx},
		{444,	&JitRecompiler::orx},
		{124,	&JitRecompiler::norx},
		{316,	&JitRecompiler::xorx},
		{412,	&JitRecompiler::orcx},
		{476,	&JitRecompiler::nandx},
		{284,	&JitRecompiler::eqvx},
		{0,		&JitRecompiler::cmp},
		{32,	&JitRecompiler::cmpl},
		{26,	&JitRecompiler::cntlzwx},
		{922,	&JitRecompiler::extshx},
		{954,	&JitRecompiler::extsbx},
		{536,	&JitRecompiler::srwx},
		{792,	&JitRecompiler::srawx},
		{824,	&JitRecompiler::srawix},
		{24,	&JitRecompiler::slwx},
		
		{54,	&JitRecompiler::dcbst},
		{86,	&JitRecompiler::dcbf},
		{246,	&JitRecompiler::dcbtst},
		{278,	&JitRecompiler::dcbt},
		{470,	&JitRecompiler::dcbi},
		{758,	&JitRecompiler::dcba},
		{1014,	&JitRecompiler::dcbz},
		
		{23,	&JitRecompiler::lwzx},
		{55,	&JitRecompiler::lwzux},
		
		{279,	&JitRecompiler::lhzx},
		{311,	&JitRecompiler::lhzux},
		
		{343,	&JitRecompiler::lhax},
		{375,	&JitRecompiler::lhaux},
		
		{87,	&JitRecompiler::lbzx},
		{119,	&JitRecompiler::lbzux},
		
		{534,	&JitRecompiler::lwbrx},
		{790,	&JitRecompiler::lhbrx},
		
		{150,	&JitRecompiler::stwcxd},
		{20,	&JitRecompiler::lwarx},
		
		{533,	&JitRecompiler::lswx},
		{597,	&JitRecompiler::lswi},
		
		{151, 	&JitRecompiler::stwx},
		{183, 	&JitRecompiler::stwux},
			
		{407, 	&JitRecompiler::sthx},
		{439, 	&JitRecompiler::sthux},
			
		{215, 	&JitRecompiler::stbx},
		{247, 	&JitRecompiler::stbux},
			
		{662, 	&JitRecompiler::stwbrx},
		{918, 	&JitRecompiler::sthbrx},
			
		{661, 	&JitRecompiler::stswx},
		{725, 	&JitRecompiler::stswi},
			
		{535, 	&JitRecompiler::lfsx},
		{567, 	&JitRecompiler::lfsux},
		{599, 	&JitRecompiler::lfdx},
		{631, 	&JitRecompiler::lfdux},
			
		{663, 	&JitRecompiler::stfsx},
		{695, 	&JitRecompiler::stfsux},
		{727, 	&JitRecompiler::stfdx},
		{759, 	&JitRecompiler::stfdux},
		{983, 	&JitRecompiler::stfiwx},
		
		{19,	&JitRecompiler::mfcr},
		{83,	&JitRecompiler::mfmsr},
		{144, 	&JitRecompiler::mtcrf},
		{146, 	&JitRecompiler::mtmsr},
		{210, 	&JitRecompiler::mtsr},
		{242, 	&JitRecompiler::mtsrin},
		{339, 	&JitRecompiler::mfspr},
		{467, 	&JitRecompiler::mtspr},
		{371, 	&JitRecompiler::mftb},
		{512, 	&JitRecompiler::mcrxr},
		{595, 	&JitRecompiler::mfsr},
		{659, 	&JitRecompiler::mfsrin},
		
		{4,		&JitRecompiler::tw},
		{598,	&JitRecompiler::sync},
		{982,	&JitRecompiler::icbi},
		
		{310, 	&JitRecompiler::eciwx},
		{438, 	&JitRecompiler::ecowx},
		{854, 	&JitRecompiler::eieio},
		{306, 	&JitRecompiler::tlbie},
		{370, 	&JitRecompiler::tlbia},
		{566, 	&JitRecompiler::tlbsync},
	};
	
	InstructionPair table31_2[] =
	{
		{266,	&JitRecompiler::addx},
		{10,	&JitRecompiler::addcx},
		{138,	&JitRecompiler::addex},
		{234,	&JitRecompiler::addmex},
		{202,	&JitRecompiler::addzex},
		{491,	&JitRecompiler::divwx},
		{459,	&JitRecompiler::divwux},
		{75,	&JitRecompiler::mulhwx},
		{11,	&JitRecompiler::mulhwux},
		{235,	&JitRecompiler::mullwx},
		{104,	&JitRecompiler::negx},
		{40,	&JitRecompiler::subfx},
		{8,		&JitRecompiler::subfcx},
		{136,	&JitRecompiler::subfex},
		{232,	&JitRecompiler::subfmex},
		{200,	&JitRecompiler::subfzex},
	};
	
	InstructionPair table59[] =
	{
		{18, 	&JitRecompiler::fdivsx},
		{20, 	&JitRecompiler::fsubsx},
		{21, 	&JitRecompiler::faddsx},
		{24, 	&JitRecompiler::fresx},
		{25, 	&JitRecompiler::fmulsx},
		{28, 	&JitRecompiler::fmsubsx},
		{29, 	&JitRecompiler::fmaddsx},
		{30, 	&JitRecompiler::fnmsubsx},
		{31, 	&JitRecompiler::fnmaddsx},
	};
	
	InstructionPair table63[] =
	{
		{264,	&JitRecompiler::fabsx},
		{32,	&JitRecompiler::fcmpo},
		{0,		&JitRecompiler::fcmpu},
		{14,	&JitRecompiler::fctiwx},
		{15,	&JitRecompiler::fctiwzx},
		{72,	&JitRecompiler::fmrx},
		{136,	&JitRecompiler::fnabsx},
		{40,	&JitRecompiler::fnegx},
		{12,	&JitRecompiler::frspx},
		
		{64,	&JitRecompiler::mcrfs},
		{583,	&JitRecompiler::mffsx},
		{70,	&JitRecompiler::mtfsb0x},
		{38,	&JitRecompiler::mtfsb1x},
		{134,	&JitRecompiler::mtfsfix},
		{711,	&JitRecompiler::mtfsfx},
	};
	
	InstructionPair table63_2[] =
	{
		{18,	&JitRecompiler::fdivx},
		{20,	&JitRecompiler::fsubx},
		{21,	&JitRecompiler::faddx},
		{22,	&JitRecompiler::fsqrtx},
		{23,	&JitRecompiler::fselx},
		{25,	&JitRecompiler::fmulx},
		{26,	&JitRecompiler::frsqrtex},
		{28,	&JitRecompiler::fmsubx},
		{29,	&JitRecompiler::fmaddx},
		{30,	&JitRecompiler::fnmsubx},
		{31,	&JitRecompiler::fnmaddx},
	};
	
	InstructionPair primaryTable[] =
	{
		{4,		&JitRecompiler::DispatchTable4},
		{19, 	&JitRecompiler::DispatchTable19},
		{31, 	&JitRecompiler::DispatchTable31},
		{59, 	&JitRecompiler::DispatchTable59},
		{63, 	&JitRecompiler::DispatchTable63},
		
		{16, 	&JitRecompiler::bcx},
		{18, 	&JitRecompiler::bx},
		
		{1, 	&JitRecompiler::Default},	// HLEFunction
		{2, 	&JitRecompiler::Default},	// DynaBlock
		{3, 	&JitRecompiler::twi},
		{17, 	&JitRecompiler::sc},
		
		{7, 	&JitRecompiler::mulli},
		{8, 	&JitRecompiler::subfic},
		{10, 	&JitRecompiler::cmpli},
		{11, 	&JitRecompiler::cmpi},
		{12, 	&JitRecompiler::addic},
		{13, 	&JitRecompiler::addic_rc},
		{14, 	&JitRecompiler::addi},
		{15, 	&JitRecompiler::addis},
		
		{20, 	&JitRecompiler::rlwimix},
		{21, 	&JitRecompiler::rlwinmx},
		{23, 	&JitRecompiler::rlwnmx},
		
		{24, 	&JitRecompiler::ori},
		{25, 	&JitRecompiler::oris},
		{26, 	&JitRecompiler::xori},
		{27, 	&JitRecompiler::xoris},
		{28, 	&JitRecompiler::andi_rc},
		{29, 	&JitRecompiler::andis_rc},
			
		{32, 	&JitRecompiler::lwz},
		{33, 	&JitRecompiler::lwzu},
		{34, 	&JitRecompiler::lbz},
		{35, 	&JitRecompiler::lbzu},
		{40, 	&JitRecompiler::lhz},
		{41, 	&JitRecompiler::lhzu},
		{42, 	&JitRecompiler::lha},
		{43, 	&JitRecompiler::lhau},
			
		{44, 	&JitRecompiler::sth},
		{45, 	&JitRecompiler::sthu},
		{36, 	&JitRecompiler::stw},
		{37, 	&JitRecompiler::stwu},
		{38, 	&JitRecompiler::stb},
		{39, 	&JitRecompiler::stbu},
			
		{46, 	&JitRecompiler::lmw},
		{47, 	&JitRecompiler::stmw},
			
		{48, 	&JitRecompiler::lfs},
		{49, 	&JitRecompiler::lfsu},
		{50, 	&JitRecompiler::lfd},
		{51, 	&JitRecompiler::lfdu},
			
		{52, 	&JitRecompiler::stfs},
		{53, 	&JitRecompiler::stfsu},
		{54, 	&JitRecompiler::stfd},
		{55, 	&JitRecompiler::stfdu},
			
		{56, 	&JitRecompiler::psq_l},
		{57, 	&JitRecompiler::psq_lu},
		{60, 	&JitRecompiler::psq_st},
		{61, 	&JitRecompiler::psq_stu},
		
		// Unknown instructions
		// Call the interpreter anyways, if it doesn't know what to do with them
		//	then it's gonna crash (which is what we would do anyways)
		{0, 	&JitRecompiler::Default},
		{5, 	&JitRecompiler::Default},
		{6, 	&JitRecompiler::Default},
		{9, 	&JitRecompiler::Default},
		{22, 	&JitRecompiler::Default},
		{30, 	&JitRecompiler::Default},
		{62, 	&JitRecompiler::Default},
		{58, 	&JitRecompiler::Default},
	};
	
	for (int i = 0; i < 32; i++)
		dispatchTable59[i] = &JitRecompiler::Default;
	
	for (int i = 0; i < 1024; i++)
	{
		dispatchTable4[i] = &JitRecompiler::Default;
		dispatchTable19[i] = &JitRecompiler::Default;
		dispatchTable31[i] = &JitRecompiler::Default;
		dispatchTable63[i] = &JitRecompiler::Default;
	}
	
	for (int i = 0; i < COUNT(primaryTable); i++)
	{
		InstructionPair pair = primaryTable[i];
		dispatchTable[pair.opcode] = pair.function;
	}
	
	for (int i = 0; i < 32; i++)
	{
		int fill = i << 5;
		for (int j = 0; j < COUNT(table4_2); j++)
		{
			InstructionPair pair = table4_2[j];
			u32 operation = fill + pair.opcode;
			dispatchTable4[operation] = pair.function;
		}
	}
	
	for (int i = 0; i < 16; i++)
	{
		int fill = i << 5;
		for (int j = 0; j < COUNT(table4_3); j++)
		{
			InstructionPair pair = table4_3[j];
			u32 operation = fill + pair.opcode;
			dispatchTable4[operation] = pair.function;
		}
	}
	
	for (int i = 0; i < COUNT(table4); i++)
	{
		InstructionPair pair = table4[i];
		dispatchTable4[pair.opcode] = pair.function;
	}
	
	for (int i = 0; i < COUNT(table31); i++)
	{
		InstructionPair pair = table31[i];
		dispatchTable31[pair.opcode] = pair.function;
	}
	
	// JIT64 has some weird for loop that "loops" only once for this case
	for (int i = 0; i < COUNT(table31_2); i++)
	{
		InstructionPair pair = table31_2[i];
		dispatchTable31[pair.opcode] = pair.function;
	}
	
	for (int i = 0; i < COUNT(table19); i++)
	{
		InstructionPair pair = table19[i];
		dispatchTable19[pair.opcode] = pair.function;
	}
	
	for (int i = 0; i < COUNT(table59); i++)
	{
		InstructionPair pair = table59[i];
		dispatchTable59[pair.opcode] = pair.function;
	}
	
	for (int i = 0; i < COUNT(table63); i++)
	{
		InstructionPair pair = table63[i];
		dispatchTable63[pair.opcode] = pair.function;
	}
	
	for (int i = 0; i < 32; i++)
	{
		int fill = i << 5;
		for (int j = 0; j < COUNT(table63_2); j++)
		{
			InstructionPair pair = table63_2[j];
			u32 operation = fill + pair.opcode;
			dispatchTable63[operation] = pair.function;
		}
	}
}

}